DialectOptions.java
package org.codefilarete.stalactite.sql;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
import org.codefilarete.stalactite.sql.statement.binder.ParameterBinder;
import org.codefilarete.tool.collection.CaseInsensitiveSet;
import org.codefilarete.tool.function.Hanger.Holder;
/**
* {@link DialectOptions} are used to adapt the SQL dialect of the database.
* @author Guillaume Mary
*/
public class DialectOptions {
public static DialectOptions noOptions() {
return new DialectOptions();
}
private final OptionalSetting<Integer> inOperatorMaxSize = new OptionalSetting<>();
private final OptionalSetting<Character> quoteCharacter = new OptionalSetting<>();
private final OptionalSetting<Boolean> quoteSQLIdentifiers = new OptionalSetting<>();
private final OptionalSetting<Set<JavaTypeToSQLType<?>>> javaTypeToSqlTypeMappings = new OptionalSetting<>();
private final OptionalSetting<Set<JavaTypeBinder<?>>> javaTypeBinders = new OptionalSetting<>();
private final OptionalSetting<Set<String>> sqlKeywordsToAdd = new OptionalSetting<>();
private final OptionalSetting<Set<String>> sqlKeywordsToRemove = new OptionalSetting<>();
public OptionalSetting<Integer> getInOperatorMaxSize() {
return inOperatorMaxSize;
}
public DialectOptions setInOperatorMaxSize(int inOperatorMaxSize) {
this.inOperatorMaxSize.set(inOperatorMaxSize);
return this;
}
public OptionalSetting<Character> getQuoteCharacter() {
return quoteCharacter;
}
public DialectOptions setQuoteCharacter(char quoteCharacter) {
this.quoteCharacter.set(quoteCharacter);
return this;
}
public OptionalSetting<Boolean> getQuoteSQLIdentifiers() {
return quoteSQLIdentifiers;
}
/**
* Sets quoting SQL Identifiers options (out of SQL keywords).
* Made to make the database respect identifier case sensitivity.
* If set to false, only SQL keywords will be quoted.
*
* @param quoteSQLIdentifiers true for quoting SQL Identifiers, false to quote only SQL keywords
* @return this
*/
public DialectOptions setQuoteSQLIdentifiers(boolean quoteSQLIdentifiers) {
this.quoteSQLIdentifiers.set(quoteSQLIdentifiers);
return this;
}
/**
* Asks for quoting all SQL Identifiers (out of SQL keywords).
* Made to make the database respect identifier case sensitivity.
*
* @return this
*/
public DialectOptions quoteSQLIdentifiers() {
return setQuoteSQLIdentifiers(true);
}
public OptionalSetting<Set<JavaTypeBinder<?>>> getJavaTypeBinders() {
return javaTypeBinders;
}
public OptionalSetting<Set<JavaTypeToSQLType<?>>> getJavaTypeToSqlTypeMappings() {
return javaTypeToSqlTypeMappings;
}
/**
* Defines the persistence of a mono-column Java type.
*
* @param javaType the Java type to define
* @param sqlType the mapped SQL type (for database schema generation)
* @param parameterBinder Java type binding (for JDBC statements usage)
* @return this
*/
public <T> DialectOptions addTypeBinding(Class<T> javaType, String sqlType, ParameterBinder<T> parameterBinder) {
setJavaTypeToSQL(javaType, sqlType);
setTypeBinding(javaType, parameterBinder);
return this;
}
/**
* Set or override a type definition (for database schema generation), either to define a new one or to change the SQL type of an existing one.
* In the former case, invoker shall also use {@link #setTypeBinding(Class, ParameterBinder)} to define its binding. Which means that
* {@link #addTypeBinding(Class, String, ParameterBinder)} should be preferred.
*
* @param javaType the Java type to be set
* @param sqlType the mapped SQL type
* @return this
*/
public DialectOptions setJavaTypeToSQL(Class<?> javaType, String sqlType) {
if (this.javaTypeToSqlTypeMappings.get() == null) {
this.javaTypeToSqlTypeMappings.set(new HashSet<>());
}
this.javaTypeToSqlTypeMappings.get().add(new JavaTypeToSQLType<>(javaType, sqlType));
return this;
}
/**
* Set or override a type binding (for JDBC statements usage), either to define a new one or to change the binding of an existing one.
* In the former case, invoker shall also use {@link #setJavaTypeToSQL(Class, String)} to define its SQL type. Which means that
* {@link #addTypeBinding(Class, String, ParameterBinder)} should be preferred.
*
* @param javaType the Java type to be set
* @param parameterBinder the mapped SQL type
* @return this
* @param <T> Java type
*/
public <T> DialectOptions setTypeBinding(Class<T> javaType, ParameterBinder<T> parameterBinder) {
if (this.javaTypeBinders.get() == null) {
this.javaTypeBinders.set(new HashSet<>());
}
this.javaTypeBinders.get().add(new JavaTypeBinder<>(javaType, parameterBinder));
return this;
}
/**
* Gives keywords to be added to the dialect.
* Made to fix a missing keyword in the vendor setting.
*
* @return keywords to be added to the dialect
*/
public OptionalSetting<Set<String>> getSqlKeywordsToAdd() {
return sqlKeywordsToAdd;
}
/**
* Adds keywords to be added to the dialect.
* @param keywords the keywords to be added
* @return this
*/
public DialectOptions addSqlKeywords(String... keywords) {
sqlKeywordsToAdd.set(new CaseInsensitiveSet(keywords));
return this;
}
/**
* Gives keywords to be removed from the dialect.
* Made to fix a not-wanted keyword in the vendor settings.
*
* @return keywords to be added to the dialect
*/
public OptionalSetting<Set<String>> getSqlKeywordsToRemove() {
return sqlKeywordsToRemove;
}
/**
* Removes some keywords from the dialect.
* @param keywords the keywords to be removed
* @return this
*/
public DialectOptions removeSqlKeywords(String... keywords) {
sqlKeywordsToRemove.set(new CaseInsensitiveSet(keywords));
return this;
}
public static class JavaTypeToSQLType<T> {
private final Class<T> javaType;
private final String sqlType;
private JavaTypeToSQLType(Class<T> javaType, String sqlType) {
this.javaType = javaType;
this.sqlType = sqlType;
}
public Class<T> getJavaType() {
return javaType;
}
public String getSqlType() {
return sqlType;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
JavaTypeToSQLType<?> that = (JavaTypeToSQLType<?>) o;
return javaType.equals(that.javaType);
}
@Override
public int hashCode() {
return javaType.hashCode();
}
}
public static class JavaTypeBinder<T> {
private final Class<T> javaType;
private final ParameterBinder<T> parameterBinder;
private JavaTypeBinder(Class<T> javaType, ParameterBinder<T> parameterBinder) {
this.javaType = javaType;
this.parameterBinder = parameterBinder;
}
public Class<T> getJavaType() {
return javaType;
}
public ParameterBinder<T> getParameterBinder() {
return parameterBinder;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
JavaTypeBinder<?> that = (JavaTypeBinder<?>) o;
return javaType.equals(that.javaType);
}
@Override
public int hashCode() {
return javaType.hashCode();
}
}
public static class OptionalSetting<T> extends Holder<T> {
private boolean touched;
public OptionalSetting() {
}
@Override
public void set(T value) {
super.set(value);
touched = true;
}
public boolean isTouched() {
return touched;
}
public T getOrDefault(T defaultValue) {
return isTouched() ? super.get() : defaultValue;
}
public void consumeIfTouched(Consumer<T> consumer) {
if (isTouched()) {
consumer.accept(get());
}
}
}
}